﻿using System;
using System.Linq;
using LINQPad.OpenAccess.Metadata;
using LINQPad.OpenAccess.Metadata.Reflection;
using LINQPad.OpenAccess.Metadata.Reflection.Adapters;
using LINQPad.OpenAccess.Metadata.Reflection.Locators;
using LINQPad.OpenAccess.Services;
using LINQPad.OpenAccess.Services.Builders;
using LINQPad.OpenAccess.Services.Descriptors;
using Ninject.Modules;

namespace LINQPad.OpenAccess.Configuration.Modules
{
    /// <summary>
    ///   <see cref="NinjectModule" /> for the current assembly.
    /// </summary>
    public class LINQPadOpenAccessModule : NinjectModule
    {
        #region Private

        #region - Functions

        /// <summary>
        /// Binds the default services.
        /// </summary>
        private void BindDefaultServices( )
        {
            this.Bind<IDataContextServices>( ).To<DataContextServices>( ).InSingletonScope( );
            this.Bind<IDataContextInitializationService>( ).To<DataContextInitializationService>( ).InSingletonScope( );
            this.Bind<IDataContextSchemaProvider>( ).To<DataContextSchemaProvider>( ).InSingletonScope( );
            this.Bind<IDataContextSettingsRepository>( )
                .ToConstructor( p => new DataContextSettingsRepository( ) )
                .InSingletonScope( );
            this.Bind<IDataContextUserInteractionService>( ).To<NullDataContextUserInteractionService>( ).InSingletonScope( );
            this.Bind<IApplicationConfigService>( ).To<ApplicationConfigService>( ).InSingletonScope( );
            this.Bind<IBackendService>( ).To<BackendService>( ).InSingletonScope( );
            this.Bind<IDataContextCustomMemberProviderFactory>( ).To<DataContextCustomMemberProviderFactory>( ).InSingletonScope( );
        }
        /// <summary>
        /// Binds the connection services.
        /// </summary>
        private void BindConnectionServices( )
        {
            // connection string builders
            this.Bind<IConnectionStringBuilderFactory>( ).To<ConnectionStringBuilderFactory>( ).InSingletonScope( );
            this.Bind<IConnectionStringBuilder>( ).To<PredefinedConnectionStringBuilder>( ).InSingletonScope( );

            // connection descriptors
            this.Bind<IDataContextConnectionDescriptionProvider>( ).To<DataContextConnectionDescriptionProvider>( ).InSingletonScope( );
            this.Bind<IConnectionDescriptor>( ).To<DefaultConnectionDescriptor>( ).InSingletonScope( );
            this.Bind<IConnectionDescriptor>( ).To<ConnectionDescriptorForUsingDefaultConstructor>( ).InSingletonScope( );
            this.Bind<IConnectionDescriptor>( ).To<PredefinedConnectionDescriptor>( ).InSingletonScope( );
        }
        /// <summary>
        /// Binds the reflection services.
        /// </summary>
        private void BindReflectionServices( )
        {
            this.Bind<IAssemblyParser>( ).To<AssemblyParser>( ).InSingletonScope( );
            this.Bind<IContextTypeLocator>( ).To<ContextTypeLocator>( ).InSingletonScope( );
            this.Bind<IMetadataSourceLocator>( ).To<XmlMetadataSourceLocator>( ).InSingletonScope( );
            this.Bind<IMetadataSourceLocator>( ).To<FluentMetadataSourceLocator>( ).InSingletonScope( );
            this.Bind<IMetadataSourceLocator>( ).To<AttributesMetadataSourceLocator>( ).InSingletonScope( );
            this.Bind<IReflectionService>( ).To<ReflectionService>( ).InSingletonScope( );
            this.Bind<IContextTypeInfoAdapter>( ).To<ContextTypeInfoAdapter>( ).InSingletonScope( );
        }

        #endregion

        #endregion

        #region NinjectModule Members

        /// <summary>
        /// Loads the module into the kernel.
        /// </summary>
        public override void Load( )
        {
            this.BindDefaultServices( );
            this.BindConnectionServices( );
            this.BindReflectionServices( );
        }

        #endregion
    }
}
